###############################################################################
#Programmers: Danil Dotsenko, dd@accentsolution.com                           #
#                                                                             #
#                                                                             #
#    Copyleft 2006,2007 Danil Dotsenko                                        #
#                                                                             #
#    This program is free software; you can redistribute it and/or modify     #
#    it under the terms of the GNU General Public License as published by     #
#    the Free Software Foundation; either version 2 of the License.           #
#                                                                             #
#    This program is distributed in the hope that it will be useful,          #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of           #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
#    GNU General Public License for more details.                             #
#                                                                             #
#    You should have received a copy of the GNU General Public License        #
#    along with this program; if not, write to the Free Software              #
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA #
#                                                                             #
###############################################################################

import re
import os
from urllib import urlretrieve

print "loaded WebImage plugin"

# note we support both, static and renewable images, and default to paused, static mode.
# There is no way to know if this is a webcam, so we will rely on the user to:
# 1. Unpause,
# 2. Set the refresh rate.
# I hope they get the fact that their webcam does not refresh and unpause.

class storageClass:
	'''
	This class helps to make the storage of temporary files easier.
	We will be storing ALL files for ALL instances of this plugin.
	'''
	def __init__(self, tempPath=None):
		if tempPath:
			self.tempPath = tempPath
		else:
			self.tempPath = '/tmp/kde-'+os.environ.get('USER')+'/afoto-webimage/'
		# this should look like /tmp/kde-username/afoto-flickr/
		if not os.path.isdir(self.tempPath):
			os.makedirs(self.tempPath)
			# think about permission settings.
	
	def addURL(self, url, refresh=False):
		'''
		Take a URL of a file, save it locally and return local path.
		If file is already found in cache, we don't download anything,
		and hapily return the path to local file.
		'''
		# 1. extract the file name out of the URL
		# 2. we will check the cache 
		# 3. and download image only if we don't have it.
		filename = os.path.dirname(url).strip('[http|ftp|https]://').replace('/','-').replace('.','-') + os.path.basename(url)
		if os.path.isfile(self.tempPath+filename) and not refresh:
			return self.tempPath+filename
		else:
			try:
				localpath, messages = urlretrieve(url, self.tempPath+filename)
				return self.tempPath+filename
			except:
				return None
	
	def searchByURL(self, url):
		'''
		Testing if URL is already saved in cache. Here we accept raw image URLs
		and return local file name if file exists already.
		'''
		# 1. extract the file name out of the URL
		# 2. we will check the cache 
		filename = os.path.dirname(url).strip('[http|ftp|https]://').replace('/','-').replace('.','-') + os.path.basename(url)
		if os.path.isfile(self.tempPath+filename):
			return self.tempPath+filename
		else:
			return None
	
	def searchLocal(self, snippet):
		'''
		Testing if text string matches any file already saved in cache.
		We return a list with local file names if files exist in storage.
		This may be useful for looking for file names incorporating IDs.
		Note: you may pass a regular expression to this formula.
		'''
		# 1. get full list of photos in the dir.
		# 2. find the snippet in the list.
		schObject = re.compile(snippet)
		filelist = []
		for root, dirs, files in os.walk(self.tempPath):
			for name in files:
				if schObject.search(name):
					filelist.append(os.path.join(root, name))
		return filelist

	def clean(self, mode='old', modeopts=24):
		'''
		Cleaning up the storage cache.
		Arguments:
		- mode can be one of "old", "size"
		- modeopts depends on mode.
		for "old" it's the time in hours from now.
		for "size" it's the maximum size of the folder in megabytes.
		NOTE A PLACEHOLDER ONLY. NOT IMPLEMENTED YET!
		'''
		pass

class pluginClass:
	'''
	Just random notes to myself. Real, helpfull comments will come later.
	'''
	def __init__(self):
		'''
		MANDATORY FUNCTION
		Init is run only ONCE, regardless of how many instance of this plugin
		are runing in all instances of afoto.
		Use this function to set and store variables that will be common for all consecutive
		instances and uses of this plugin.
		'''
		
		# MANDATORY VARIABLES
		self.filterStr = '^http://.+\.(jpg|jpeg|png|gif|bmp)$'
		self.filterObj = None # this will be re.compile object, populated by main afoto code based on the filter above.
		self.protocol = 'webimage' 
		# this refers to nice, internal, imagined URLS, like "flickr" or "asdf"
		# I am not sure how to use this yet,
		# I may instead populate this based on what .INI file says.
		# so, don't rely on / set protocol here just yet.
		# the value may vary depending on what INI file says when it calls this plugin.
		# and will likely be populated by main afoto code upon plugin initialization.
		# when I make my mind, I will change this message.

		# OPTIONAL VARIABLES
		self.storage = storageClass()
	
	def translatePath(self, path):
		'''
		MANDATORY FUNCTION
		This function would convert a usual url into internally stored url
		example: http://flickr.com/name/album/ would turn into flickr://id:APInum@blah/blah
		Some URLs, like "file://" are returned in the same way back
		This is used for quick identification of already used urls by plugin matching algorythm.
		Include all the username and password requests in this function and put all the info into 
		our made up URL. This way the user is only bothered by it once.
		'''
		# someday we'll think about storing commonly-used user-input data permanently in the afoto config file.
		# until then, store it ind ask for it every time a new path is dropped in.
		# we will just cange the protocol part of URL - replace "http" with "webimage"
		# to result in something like "webimage://asdf.asfd.com/asfd/imagefile.png"
		if path[:4] == "http":
			path = self.protocol+path[4:]
		return path
	
	def revertPath(self, path):
		'''
		OPTIONAL FUNCTION
		This is an optional, helper function that converts our custom url back into real url.
		example: flickr://id:APInum@blah/blah would turn into http://flickr.com/name/album/ 
		This is only for use in your plug in, and doesn't have to be included
		'''
		# we will just cange the protocol part of URL - replace "webimage" with "http"
		# to result in something like "http://asdf.asfd.com/asfd/imagefile.png"
		if path[:(self.protocol.__len__())] == self.protocol:
			path = 'http'+path[(self.protocol.__len__()):]
		return path

	def tryNextImage(self, widget, instance, common, customPath = None):
		'''
		MANDATORY FUNCTION
		This function prepares the image for consumption by setting a valid source to instance.cfg['currentPath']
		and changing instance.cfg['resourcePath'] in case when completely new source was dropped / chosen
		widget = widget mumber.
		common = pointer to appConfig.common a dictionary type with afoto-wide settings.
		instance = pointer to appConfig.instance[widget] a dictionary type with instance-specific settings.
		  instance.cfg['resourcePath'] already contains a proven, used source. 
		  if customPath is not usable or is not given, we will need to pull a new item out of instance.cfg['resourcePath']
		customPath = string (or unicode type) with new path we need to test.
		  (NOTE! It was already converted into our internal imaginary URL protocol by afoto's main code.
		  It used the translatePath() function.)
		  We test if that path is workable and try to pull a picture, If OK, we make it a new resourcePath
		'''
		
		# FOR PLUGIN WRITERS:
		# there are 4 things that have to happen in this function:
		# 0. if customPath is given, we translate the normal URL into our internal URL.
		#	  (main Afoto code already matched it to this plugin and translated it)
		# 1. test the path (new from customPath or old from instance.cfg['resourcePath'])
		# 2. if path is ok, pull up a picture to the local drive and set the address to the file to instance.cfg['currentPath']
		# 3. if we used customPath for the source, reset instance.cfg['resourcePath'] to the new address
		# 4. Change the Return value (success) to True if we really changed and prepared the image
		
		# NOTE! This function is called by all instances of afoto containing this plugin.
		# do not use constant names for temp files, of you will have a mess when more than one of this plugin is running.
		# add widget number to the file names to keep many instances of afoto separate.

		# Part 1 testing the path

		success = False # This will mean: Nothing is changed, do not redraw

		if customPath:
			# it was dropped in or passed through URLOpen dialog and may be in raw format.
			# Again: It was already converted into our internal imaginary URL protocol by afoto's main code.
			testPath = customPath
		else:
			# this means we are just reloading from the same, known location.
			testPath = instance.cfg['resourcePath']
		
		# Small plan of attack for http protocol.
		# - Create / Test a temp location for the image storage.
		# - Pull the image there.
		# - Test that file has size. (not sure how to test that image IS image.)
		# - Send success (no need to change any vars, if it's the same temp file.)

		localpath = self.storage.addURL(self.revertPath(testPath), True)
		
		# now, let's test that we got it.
		if localpath:
			# WARNING!!!!!
			# self.tempFile MUST be a local path of form "/folder/folder/filename"
			# It cannot contain "file://"
			# I have seen local image FILES DISAPPEAR when superkaramba crashes because of
			# loading URL's with "file://"
			instance.cfg['currentPath'] = localpath
			if customPath:
				# meaning , if this path was dropped in / new.
				instance.cfg['resourcePath'] = customPath # note, it is already converted into internal URL.
				instance.pause(widget)
			success = True
		return success
